﻿namespace SmartAnswerPlatform.Common
{
    public class IdGenerator
    {
        // ================ 配置参数（可自定义） ================
        private const long Epoch = 1672531200000L; // 纪元时间（默认：2023-01-01）
        private const int TimestampBits = 41;       // 时间戳位数（默认41位，支持69年）
        private const int WorkerIdBits = 5;         // 工作节点ID位数（默认5位，支持32节点）
        private const int DatacenterIdBits = 5;     // 数据中心ID位数（默认5位，支持32中心）
        private const int SequenceBits = 12;        // 序列号位数（默认12位，每毫秒4096个ID）

        // ================ 位移量计算（无需修改） ================
        private const int WorkerIdShift = SequenceBits;
        private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
        private const int TimestampShift = SequenceBits + WorkerIdBits + DatacenterIdBits;
        private const long SequenceMask = -1L ^ (-1L << SequenceBits); // 序列号掩码（4095）

        // ================ 运行时状态 ================
        private static readonly object _lock = new();
        private static long _lastTimestamp = -1L;
        private static long _sequence = 0L;

        public static long WorkerId { get; } = 1;
        public static long DatacenterId { get; } = 1;


        public static string NextId()
        {
            lock (_lock) // 确保多线程安全
            {
                long timestamp = GetCurrentTimestamp();

                // 处理时钟回拨（抛出异常防止ID重复）
                if (timestamp < _lastTimestamp)
                    throw new Exception($"时钟回拨！拒绝生成ID。当前时间：{timestamp}，上次时间：{_lastTimestamp}");

                // 同一毫秒内生成ID
                if (timestamp == _lastTimestamp)
                {
                    _sequence = (_sequence + 1) & SequenceMask;
                    if (_sequence == 0) // 序列号溢出，等待下一毫秒
                        timestamp = WaitNextMillis(_lastTimestamp);
                }
                else // 新毫秒重置序列号
                {
                    _sequence = 0;
                }

                _lastTimestamp = timestamp;

                // 拼接64位ID：时间戳 | 数据中心 | 工作节点 | 序列号
                long Id = ((timestamp - Epoch) << TimestampShift)
                       | (DatacenterId << DatacenterIdShift)
                       | (WorkerId << WorkerIdShift)
                       | _sequence;
                return Id.ToString();
            }
        }

        private static long GetCurrentTimestamp()
        {
            return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
        }

        private static long WaitNextMillis(long lastTimestamp)
        {
            long timestamp = GetCurrentTimestamp();
            while (timestamp <= lastTimestamp)
            {
                System.Threading.Thread.Sleep(1); // 阻塞1毫秒
                timestamp = GetCurrentTimestamp();
            }
            return timestamp;
        }
    }
}
